package com.baize.filedowndemo.autoupdate

import android.app.Application
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.baize.filedowndemo.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.File
import java.io.RandomAccessFile
import java.util.concurrent.TimeUnit

class DownloadWorker(context: Context, parameters: WorkerParameters) :
  CoroutineWorker(context, parameters) {

  private val notificationManager =
    context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

  override suspend fun doWork(): Result { //url null直接成功
    val srcUrl = inputData.getString(KEY_URL) ?: return Result.success()
    val fileName = srcUrl.substring(srcUrl.lastIndexOf("/"))
    val outputFileUri = """${applicationContext.cacheDir.path}$fileName"""
    val file = File(outputFileUri)
    if (file.exists()) { //用户未安装文件而已
      Log.i("DownloadWorker", "文件已下载成功") //这是一个全局的通知消息队列，继承自LiveData<T>，重写postValue入队
      //出队是一个可挂起的协程，延时递归清空队列显示消息。$NEW_VERSION_TIP固定字段会被监控。
      //      Application.msg.postValue("$NEW_VERSION_TIP$outputFileUri")
      return Result.success()
    }
    Log.i("DownloadWorker", "$srcUrl to $outputFileUri") // Mark the Worker as important
    val progress = "Starting Download"
    setForeground(createForegroundInfo(progress))
    return withContext(Dispatchers.IO) { download(srcUrl, outputFileUri) }
  }

  private suspend fun download(srcUrl: String, outputFileUri: String): Result {
    val partNameUri = outputFileUri.replace(".apk", ".park") //.part 保存未下载完成的文件
    val file = File(partNameUri)
    val downloadedLength = if (file.exists()) {
      file.length()
    } else 0L //val contentLength = getContentLength(srcUrl)
    val client =
      OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS)
        .build()
    val request = Request.Builder().addHeader("RANGE", "bytes=$downloadedLength-").url(srcUrl) //
      .build() //val response = client.newCall(request).execute()
    val response = client.newCall(request).execute()
    if (!response.isSuccessful) {
      return Result.retry()
    }
    response.body?.let { responseBody ->
      val contentLength = responseBody.contentLength()
      Log.i("DownloadWorker", "$contentLength")
      responseBody.byteStream().use { inputStream ->
        RandomAccessFile(partNameUri, "rw").use { randomAccessFile ->
          randomAccessFile.seek(downloadedLength)
          val buf = ByteArray(1024)
          var rLen = 0
          var total = downloadedLength // kotlin IO有更优雅的写法，这里为了满足断点续传
          while (inputStream.read(buf).also { rLen = it } != -1) {
            total += rLen;
            randomAccessFile.write(buf, 0, rLen) // setForeground 调用台频繁会导致ui卡顿
            //setForeground(createForegroundInfo((total * 100 / contentLength).toString()))
          }
          file.renameTo(File(outputFileUri))
//          Application.msg.postValue("$NEW_VERSION_TIP$outputFileUri")
        }
      }
    } // Downloads a file and updates bytes read
    // Calls setForegroundInfo() periodically when it needs to update
    // the ongoing Notification
    return Result.success()
  }


  // Creates an instance of ForegroundInfo which can be used to update the
  // ongoing notification.
  private fun createForegroundInfo(progress: String): ForegroundInfo {
    Log.i("DownloadWorker", progress)
    val id = applicationContext.getString(R.string.notification_channel_id)
    val title = applicationContext.getString(R.string.notification_title)
    val cancel = applicationContext.getString(R.string.cancel_download) // This PendingIntent can be used to cancel the worker
    val intent = WorkManager.getInstance(applicationContext).createCancelPendingIntent(getId())

    // Create a Notification channel if necessary
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      createChannel()
    }

    val notification =
      NotificationCompat.Builder(applicationContext, id).setContentTitle(title).setTicker(title)
        .setContentText(progress).setSmallIcon(R.drawable.ic_launcher_foreground)
        .setOngoing(true) // Add the cancel action to the notification which can
        // be used to cancel the worker
        .addAction(android.R.drawable.ic_delete, cancel, intent)
        .build()

    return ForegroundInfo(22, notification)
  }

  //8.0以上需要适配渠道
  @RequiresApi(Build.VERSION_CODES.O)
  private fun createChannel() { // Create a Notification channel
  }
}
